package com.h2.gwt.util.appstorage;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Cookies;

public class AppStorage {
   
   private String _storageName;
   
   private String _storeStr;
   
   private Map<String, String> _storeCache;
   
   ////
   ////
   
   public AppStorage() {
      //nothing to do
   }
   
   public void init() {
      setStorageName("APP_STORAGE");
      setStoreStr("");
      setStoreCache(new HashMap<String, String>());
   }
   
   public void update() {
      readStorage();
   }
   
   public String get(String key) {
      readStorage();
      return getStoreCache().get(key);
   }
   
   public void put(String key, String value) {
      
      readStorage();
      if(!getStoreCache().containsKey(key)) {
         getStoreCache().put(key, value);
         
         //just append it
         setStoreStr(getStoreStr()
                  + URL.encode(';' + key + '=' + value));
      }
      else {
         getStoreCache().put(key, value);
         
         //write a new string
         setStoreStr(writeStorage());
      }
      
      //write back to cookie
      writeToCookie();
   }
   
   public void putAll(Map<String, String> map) {
      readStorage();
      getStoreCache().putAll(map);
      //write the new values
      setStoreStr(writeStorage());
      writeToCookie();
   }
   
   private void writeToCookie() {
      if(Cookies.isCookieEnabled()) {
         Cookies.setCookie(getStorageName(),
               getStoreStr(),
               //2 weeks
               new Date((new Date()).getTime()
                     + 3600 * 60 * 24 * 7 * 2),
               null, "/", false);
      }
   }
   
   private void readStorage() {
      String storage = null;
      if(Cookies.isCookieEnabled()) {
         storage = Cookies.getCookie(getStorageName());
         if(storage == null) {
            return;
         }
      }
      else {
         return;
      }
      
      if (storage.length() != getStoreStr().length()) {
         updateStorage(storage);
      }
      else if (!storage.equals(getStoreStr())) {
         updateStorage(storage);
      }
   }

   private void updateStorage(String storage) {
      
      String decodedStorageStr = URL.decode(storage);
      
      setStoreStr(decodedStorageStr);
      getStoreCache().clear();
      
      String[] storageArr = decodedStorageStr.split(";");
      if(storageArr == null || storageArr.length <= 0) {
         return;
      }
      
      for (String nameValue : storageArr) {
         String[] pair = nameValue.split("=");
         getStoreCache().put(pair[0], pair[1]);
      }
   }
   
   private String writeStorage() {
      StringBuilder builder = new StringBuilder("");
      for (Map.Entry<String, String> entry : getStoreCache().entrySet()) {
         builder.append(entry.getKey());
         builder.append('=');
         builder.append(entry.getValue());
         builder.append(';');
      }
      if(builder.length() > 0) {
         builder.deleteCharAt(builder.length() - 1);
      }
      return URL.encode(builder.toString());
   }

   /**
    * @return the storageName
    */
   public String getStorageName() {
      return _storageName;
   }

   /**
    * @param storageName the storageName to set
    */
   public void setStorageName(String storageName) {
      _storageName = storageName;
   }

   /**
    * @return the storeCache
    */
   public Map<String, String> getStoreCache() {
      return _storeCache;
   }

   /**
    * @param storeCache the storeCache to set
    */
   public void setStoreCache(Map<String, String> storeCache) {
      _storeCache = storeCache;
   }

   /**
    * @return the storeStr
    */
   public String getStoreStr() {
      return _storeStr;
   }

   /**
    * @param storeStr the storeStr to set
    */
   public void setStoreStr(String storeStr) {
      _storeStr = storeStr;
   }

}
